#include <linux/module.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/kfifo.h>

#define BUF_SIZE 64
#define KFIFO 
DEFINE_KFIFO(kbuf,char,BUF_SIZE);

struct c0_dev{
	struct device *dev_c0;
	char buf[BUF_SIZE];
};
struct c0_dev *c0;


int c0_open(struct inode *inode,struct file *file)
{
	int major=MAJOR(inode->i_rdev);
	int minor=MINOR(inode->i_rdev);
	printk("%s major : %d, minor : %d\n",__func__,major,minor);
	return 0;
}
int c0_close(struct inode *inode,struct file *file)
{
	printk("%s\n",__func__);
	return 0;
}

#ifdef KFIFO
ssize_t c0_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
	int readed_size;
	int ret;
	ret = kfifo_to_user(&kbuf,buf,count,&readed_size);
	if(ret)
		return -EIO;
	printk("readed_size = %d, pos = %lld\n",readed_size,*ppos);
	return readed_size;
}
ssize_t c0_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
	int written_size;
	int ret;
	ret = kfifo_from_user(&kbuf,buf,count,&written_size);
	if(ret)
		return -EIO;
	printk("written_size = %d, pos = %lld\n",written_size,*ppos);
	return written_size;
}

#else

ssize_t c0_read(struct file *filp,char __user *buf,size_t count,loff_t *ppos)
{
	printk("%s\n",__func__);
	int readed_size,remain_size,free_size;
	int ret;
	free_size = BUF_SIZE - *ppos;
	remain_size = free_size > count? count : free_size;
	if(remain_size==0)
		dev_warn(c0->dev_c0,"no space read");
	ret = copy_to_user(buf,c0->buf+*ppos,remain_size);
	if(ret == remain_size)
		return -EFAULT;
	readed_size = remain_size - ret;
	*ppos += readed_size;

	printk("readed_size = %d , pos = %lld \n", readed_size,*ppos);
	return readed_size;
}
ssize_t c0_write(struct file *filp,const char __user *buf,size_t count,loff_t *ppos)
{
	printk("%s\n",__func__);
	int written_size,remain_size,free_size;
	int ret;
	free_size = BUF_SIZE - *ppos;
	remain_size = free_size > count? count : free_size;
	if(remain_size==0)
		dev_warn(c0->dev_c0,"no space write");
	ret = copy_from_user(c0->buf+*ppos,buf,remain_size);
	if(ret == remain_size)
		return -EFAULT;
	written_size = remain_size - ret;
	*ppos += written_size;

	printk("written_size = %d , pos = %lld \n", written_size, *ppos);
	return written_size;
}
#endif

const struct file_operations c0_fops={
	.open    = c0_open,
	.read    = c0_read,
	.write   = c0_write,
	.release = c0_close,
};

struct miscdevice misc_c0={
	.minor = MISC_DYNAMIC_MINOR,
	.name  = "misc_c0",
	.fops  = &c0_fops, 
};

static int __init dev_init(void)
{
	int ret;
	c0=(struct c0_dev*)kmalloc(sizeof(struct c0_dev),GFP_KERNEL);
	ret=misc_register(&misc_c0);
	if (ret)
	{
		printk("misc register failed\n");
		return ret;
	}
	c0->dev_c0=misc_c0.this_device;
	printk("register device misc_c0\n");
	return 0;

}

static void __exit dev_exit(void)
{
	printk("----%s----\n",__func__);
	misc_deregister(&misc_c0);
	kfree(c0);
}

module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");

